﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace SpriteMaker
{
    class Util
    {
        public static bool PointInRect(int xp, int yp, int xr, int yr, int wr, int hr)
        {
            return !(xp < xr || yp < yr || xp > xr + wr || yp > yr + hr);
        }
        public static double Distance(int x1, int y1, int x2, int y2)
        {
            return Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2));
        }
        public static SizeF SizeNormalize(SizeF size)
        {
            SizeF result = new SizeF();
            if (size.Width <= 0 || size.Height <= 0) return result;
            float min = Math.Min(size.Width, size.Height);
            result.Width = size.Width/min;
            result.Height = size.Height/min;
            return result;
        }
        public static Color RGB565ToARGB8888(UInt16 c)
        {
            int r5 = c >> 11;
            int g6 = (c >> 5) & 0x3F;
            int b5 = c & 0x1F;
            int r8 = (r5 * 255) / 31;
            int g8 = (g6 * 255) / 63;
            int b8 = (b5 * 255) / 31;
            return Color.FromArgb(r8, g8, b8);
        }
        public static Bitmap DDSToBitmap(byte[] data)
        {
            DDS dds = new DDS();
            int pointer = 0;
            dds.dwMagic = BitConverter.ToUInt32(data, pointer);
            if (dds.dwMagic != 0x20534444) //DDS
            {
                return null;
            }
            pointer += 4;
            dds.header.dwSize = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            dds.header.dwFlags = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            dds.header.dwHeight = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            dds.header.dwWidth = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            dds.header.dwPitchOrLinearSize = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            dds.header.dwDepth = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            dds.header.dwMipMapCount = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            //dwReserved1
            pointer += 11*4;
            {
                dds.header.ddspf.dwSize = BitConverter.ToUInt32(data, pointer);
                pointer += 4;
                dds.header.ddspf. dwFlags = BitConverter.ToUInt32(data, pointer);
                pointer += 4;
                dds.header.ddspf. dwFourCC = BitConverter.ToUInt32(data, pointer);
                pointer += 4;
                dds.header.ddspf. dwRGBBitCount = BitConverter.ToUInt32(data, pointer);
                pointer += 4;
                dds.header.ddspf. dwRBitMask = BitConverter.ToUInt32(data, pointer);
                pointer += 4;
                dds.header.ddspf. dwGBitMask = BitConverter.ToUInt32(data, pointer);
                pointer += 4;
                dds.header.ddspf. dwBBitMask = BitConverter.ToUInt32(data, pointer);
                pointer += 4;
                dds.header.ddspf. dwABitMask = BitConverter.ToUInt32(data, pointer);
                pointer += 4;
            }
            dds.header.dwCaps = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            dds.header.dwCaps2 = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            dds.header.dwCaps3 = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            dds.header.dwCaps4 = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            dds.header.dwReserved2 = BitConverter.ToUInt32(data, pointer);
            pointer += 4;
            Bitmap bm = new Bitmap((int)dds.header.dwWidth, (int)dds.header.dwHeight);
            String format = Encoding.ASCII.GetString(BitConverter.GetBytes(dds.header.ddspf.dwFourCC), 0, 4);
            uint blockNumber = dds.header.dwWidth * dds.header.dwHeight / 16;
            if(String.Compare(format, "DXT5", true) == 0)
            {
                byte[] block = new byte[16];
                for (int i = 0; i < blockNumber; i++)
                {
                    int imageX = (int)((i % (dds.header.dwWidth / 4))*4);
                    int imageY = (int)((i / (dds.header.dwWidth / 4)) * 4);
                    Array.Copy(data, pointer, block, 0, 16);
                    pointer += 16;
                    byte[] alphaTable = new byte[8];
                    alphaTable[0] = block[0];
                    alphaTable[1] = block[1];
                    if (alphaTable[0] > alphaTable[1])
                    {
                        // 6 interpolated alpha values.
                        alphaTable[2] = (byte)(6.0 / 7.0 * alphaTable[0] + 1.0 / 7.0 * alphaTable[1]); // bit code 010
                        alphaTable[3] = (byte)(5.0 / 7.0 * alphaTable[0] + 2.0 / 7.0 * alphaTable[1]); // bit code 011
                        alphaTable[4] = (byte)(4.0 / 7.0 * alphaTable[0] + 3.0 / 7.0 * alphaTable[1]); // bit code 100
                        alphaTable[5] = (byte)(3.0 / 7.0 * alphaTable[0] + 4.0 / 7.0 * alphaTable[1]); // bit code 101
                        alphaTable[6] = (byte)(2.0 / 7.0 * alphaTable[0] + 5.0 / 7.0 * alphaTable[1]); // bit code 110
                        alphaTable[7] = (byte)(1.0 / 7.0 * alphaTable[0] + 6.0 / 7.0 * alphaTable[1]); // bit code 111
                    }
                    else
                    {
                        // 4 interpolated alpha values.
                        alphaTable[2] = (byte)(4.0 / 5.0 * alphaTable[0] + 1.0 / 5.0 * alphaTable[1]); // bit code 010
                        alphaTable[3] = (byte)(3.0 / 5.0 * alphaTable[0] + 2.0 / 5.0 * alphaTable[1]); // bit code 011
                        alphaTable[4] = (byte)(2.0 / 5.0 * alphaTable[0] + 3.0 / 5.0 * alphaTable[1]); // bit code 100
                        alphaTable[5] = (byte)(1.0 / 5.0 * alphaTable[0] + 4.0 / 5.0 * alphaTable[1]); // bit code 101
                        alphaTable[6] = 0;                         // bit code 110
                        alphaTable[7] = 255;                       // bit code 111
                    }
                    UInt64 alphaBlock = (UInt64)(((UInt64)block[4] << 40) | ((UInt64)block[3] << 32) | ((UInt64)block[2] << 24)
                                        | ((UInt64)block[7] << 16) | ((UInt64)block[6] << 8) | ((UInt64)block[5])); //48bit
                    Color[] colorTable = new Color[4];
                    UInt16 colorMin = (UInt16)(((UInt16)block[9] << 8) | ((UInt16)block[8]));
                    UInt16 colorMax = (UInt16)(((UInt16)block[11] << 8) | ((UInt16)block[10]));
                    colorTable[0] = RGB565ToARGB8888(colorMin);
                    colorTable[1] = RGB565ToARGB8888(colorMax);
                    UInt16 r5 = (UInt16)(2.0 / 3.0 * (colorMin >> 11) + 1.0 / 3.0 * (colorMax >> 11));
                    UInt16 g6 = (UInt16)(2.0 / 3.0 * ((colorMin >> 5) & 0x3F) + 1.0 / 3.0 * ((colorMax >> 5) & 0x3F));
                    UInt16 b5 = (UInt16)(2.0 / 3.0 * (colorMin & 0x1F) + 1.0 / 3.0 * (colorMax & 0x1F));
                    UInt16 rgb565 = (UInt16)((r5 << 11) | (g6 << 5) | b5);
                    colorTable[2] = RGB565ToARGB8888(rgb565);
                    r5 = (UInt16)(1.0 / 3.0 * (colorMin >> 11) + 2.0 / 3.0 * (colorMax >> 11));
                    g6 = (UInt16)(1.0 / 3.0 * ((colorMin >> 5) & 0x3F) + 2.0 / 3.0 * ((colorMax >> 5) & 0x3F));
                    b5 = (UInt16)(1.0 / 3.0 * (colorMin & 0x1F) + 2.0 / 3.0 * (colorMax & 0x1F));
                    rgb565 = (UInt16)((r5 << 11) | (g6 << 5) | b5);
                    colorTable[3] = RGB565ToARGB8888(rgb565);
                    UInt32 colorBlock = (UInt32)(((UInt32)block[12] << 24) | ((UInt32)block[13] << 16) | ((UInt32)block[14] << 8)
                                        | ((UInt32)block[15]));
                    for (int x = 0; x < 16; x++)
                    {
                        int alphaIndex = (int)((alphaBlock >> (24 + 3*(x%8) - 24*(x/8))) & 0x7);
                        byte pixelAlpha = alphaTable[alphaIndex];
                        int colorIndex = (int)((colorBlock >> (24 + 2*(x % 4) - 8*(x / 4))) & 0x3);
                        Color pixelRGB = colorTable[colorIndex];
                        Color pixelARGB = Color.FromArgb(pixelAlpha, pixelRGB.R, pixelRGB.G, pixelRGB.B);
                        bm.SetPixel(imageX + (x % 4), imageY + (x/4), pixelARGB);
                    }
                }
            }
            return bm;
        }
    }
    class DDS
    {
        public uint dwMagic;
        public DDS_HEADER header = new DDS_HEADER();
        public DDS_HEADER_DXT10 header10;
        public byte[] bdata;
        public byte[] bdata2;

    }
    class DDS_HEADER
    {
        public uint dwSize;
        public uint dwFlags;
        public uint dwHeight;
        public uint dwWidth;
        public uint dwPitchOrLinearSize;
        public uint dwDepth;
        public uint dwMipMapCount;
        public uint[] dwReserved1 = new uint[11];
        public DDS_PIXELFORMAT ddspf = new DDS_PIXELFORMAT();
        public uint dwCaps;
        public uint dwCaps2;
        public uint dwCaps3;
        public uint dwCaps4;
        public uint dwReserved2;
    }
    class DDS_HEADER_DXT10
    {
        public DXGI_FORMAT dxgiFormat;
        public D3D10_RESOURCE_DIMENSION resourceDimension;
        public uint miscFlag;
        public uint arraySize;
        public uint miscFlags2;
    }
    class DDS_PIXELFORMAT
    {
        public uint dwSize;
        public uint dwFlags;
        public uint dwFourCC;
        public uint dwRGBBitCount;
        public uint dwRBitMask;
        public uint dwGBitMask;
        public uint dwBBitMask;
        public uint dwABitMask;
    }
    enum D3D10_RESOURCE_DIMENSION
    {
        D3D10_RESOURCE_DIMENSION_UNKNOWN = 0,
        D3D10_RESOURCE_DIMENSION_BUFFER = 1,
        D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2,
        D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3,
        D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4
    }
    enum DXGI_FORMAT
    {
        DXGI_FORMAT_UNKNOWN = 0,
        DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
        DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
        DXGI_FORMAT_R32G32B32A32_UINT = 3,
        DXGI_FORMAT_R32G32B32A32_SINT = 4,
        DXGI_FORMAT_R32G32B32_TYPELESS = 5,
        DXGI_FORMAT_R32G32B32_FLOAT = 6,
        DXGI_FORMAT_R32G32B32_UINT = 7,
        DXGI_FORMAT_R32G32B32_SINT = 8,
        DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
        DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
        DXGI_FORMAT_R16G16B16A16_UNORM = 11,
        DXGI_FORMAT_R16G16B16A16_UINT = 12,
        DXGI_FORMAT_R16G16B16A16_SNORM = 13,
        DXGI_FORMAT_R16G16B16A16_SINT = 14,
        DXGI_FORMAT_R32G32_TYPELESS = 15,
        DXGI_FORMAT_R32G32_FLOAT = 16,
        DXGI_FORMAT_R32G32_UINT = 17,
        DXGI_FORMAT_R32G32_SINT = 18,
        DXGI_FORMAT_R32G8X24_TYPELESS = 19,
        DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
        DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
        DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
        DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
        DXGI_FORMAT_R10G10B10A2_UNORM = 24,
        DXGI_FORMAT_R10G10B10A2_UINT = 25,
        DXGI_FORMAT_R11G11B10_FLOAT = 26,
        DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
        DXGI_FORMAT_R8G8B8A8_UNORM = 28,
        DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
        DXGI_FORMAT_R8G8B8A8_UINT = 30,
        DXGI_FORMAT_R8G8B8A8_SNORM = 31,
        DXGI_FORMAT_R8G8B8A8_SINT = 32,
        DXGI_FORMAT_R16G16_TYPELESS = 33,
        DXGI_FORMAT_R16G16_FLOAT = 34,
        DXGI_FORMAT_R16G16_UNORM = 35,
        DXGI_FORMAT_R16G16_UINT = 36,
        DXGI_FORMAT_R16G16_SNORM = 37,
        DXGI_FORMAT_R16G16_SINT = 38,
        DXGI_FORMAT_R32_TYPELESS = 39,
        DXGI_FORMAT_D32_FLOAT = 40,
        DXGI_FORMAT_R32_FLOAT = 41,
        DXGI_FORMAT_R32_UINT = 42,
        DXGI_FORMAT_R32_SINT = 43,
        DXGI_FORMAT_R24G8_TYPELESS = 44,
        DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
        DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
        DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
        DXGI_FORMAT_R8G8_TYPELESS = 48,
        DXGI_FORMAT_R8G8_UNORM = 49,
        DXGI_FORMAT_R8G8_UINT = 50,
        DXGI_FORMAT_R8G8_SNORM = 51,
        DXGI_FORMAT_R8G8_SINT = 52,
        DXGI_FORMAT_R16_TYPELESS = 53,
        DXGI_FORMAT_R16_FLOAT = 54,
        DXGI_FORMAT_D16_UNORM = 55,
        DXGI_FORMAT_R16_UNORM = 56,
        DXGI_FORMAT_R16_UINT = 57,
        DXGI_FORMAT_R16_SNORM = 58,
        DXGI_FORMAT_R16_SINT = 59,
        DXGI_FORMAT_R8_TYPELESS = 60,
        DXGI_FORMAT_R8_UNORM = 61,
        DXGI_FORMAT_R8_UINT = 62,
        DXGI_FORMAT_R8_SNORM = 63,
        DXGI_FORMAT_R8_SINT = 64,
        DXGI_FORMAT_A8_UNORM = 65,
        DXGI_FORMAT_R1_UNORM = 66,
        DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
        DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
        DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
        DXGI_FORMAT_BC1_TYPELESS = 70,
        DXGI_FORMAT_BC1_UNORM = 71,
        DXGI_FORMAT_BC1_UNORM_SRGB = 72,
        DXGI_FORMAT_BC2_TYPELESS = 73,
        DXGI_FORMAT_BC2_UNORM = 74,
        DXGI_FORMAT_BC2_UNORM_SRGB = 75,
        DXGI_FORMAT_BC3_TYPELESS = 76,
        DXGI_FORMAT_BC3_UNORM = 77,
        DXGI_FORMAT_BC3_UNORM_SRGB = 78,
        DXGI_FORMAT_BC4_TYPELESS = 79,
        DXGI_FORMAT_BC4_UNORM = 80,
        DXGI_FORMAT_BC4_SNORM = 81,
        DXGI_FORMAT_BC5_TYPELESS = 82,
        DXGI_FORMAT_BC5_UNORM = 83,
        DXGI_FORMAT_BC5_SNORM = 84,
        DXGI_FORMAT_B5G6R5_UNORM = 85,
        DXGI_FORMAT_B5G5R5A1_UNORM = 86,
        DXGI_FORMAT_B8G8R8A8_UNORM = 87,
        DXGI_FORMAT_B8G8R8X8_UNORM = 88,
        DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89,
        DXGI_FORMAT_B8G8R8A8_TYPELESS = 90,
        DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91,
        DXGI_FORMAT_B8G8R8X8_TYPELESS = 92,
        DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93,
        DXGI_FORMAT_BC6H_TYPELESS = 94,
        DXGI_FORMAT_BC6H_UF16 = 95,
        DXGI_FORMAT_BC6H_SF16 = 96,
        DXGI_FORMAT_BC7_TYPELESS = 97,
        DXGI_FORMAT_BC7_UNORM = 98,
        DXGI_FORMAT_BC7_UNORM_SRGB = 99,
        DXGI_FORMAT_AYUV = 100,
        DXGI_FORMAT_Y410 = 101,
        DXGI_FORMAT_Y416 = 102,
        DXGI_FORMAT_NV12 = 103,
        DXGI_FORMAT_P010 = 104,
        DXGI_FORMAT_P016 = 105,
        DXGI_FORMAT_420_OPAQUE = 106,
        DXGI_FORMAT_YUY2 = 107,
        DXGI_FORMAT_Y210 = 108,
        DXGI_FORMAT_Y216 = 109,
        DXGI_FORMAT_NV11 = 110,
        DXGI_FORMAT_AI44 = 111,
        DXGI_FORMAT_IA44 = 112,
        DXGI_FORMAT_P8 = 113,
        DXGI_FORMAT_A8P8 = 114,
        DXGI_FORMAT_B4G4R4A4_UNORM = 115,
        DXGI_FORMAT_FORCE_UINT = unchecked((int)0xffffffffUL)
    }
    class RGB565
    {
        private UInt16 data;

        public UInt16 value
        {
            get { return data; }
        }
        public byte r
        {
            get { return (byte)((data >> 11) & 0x0000001F); }
            set { data = (UInt16)((data & 0x000003FF)|value << 11); }
        }
        public byte g
        {
            get { return (byte)((data >> 5) & 0x0000003F); }
            set { data = (UInt16)((data & 0x0000F81F) | value << 5); }
        }
        public byte b
        {
            get { return (byte)((data >> 11) & 0x0000001F); }
            set { data = (UInt16)((data & 0x0000FFE0) | value); }
        }
        public void SetValue(UInt16 v)
        {
            data = v;
        }
    }
}
